pragma Ada_2012;
with Ada.Streams; use Ada.Streams;
with Ada.Streams.Stream_IO;
with Ada.Unchecked_Deallocation;
with Ada.Unchecked_Conversion;
with System, System.Storage_Elements;
with IO_Utils;
with SDL, SDL.Video, SDL.Error; use SDL;
with Cairo, Cairo.Context, Cairo.Surface, Cairo.Surface.Image;
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
with Ada.Containers; use Ada.Containers;
with Ada.Containers.Hashed_Sets;
with Ada.Containers.Doubly_Linked_Lists;
with GNAT.Random_Numbers;
with Interfaces; use Interfaces;
with Interfaces.C;
with Ada.Calendar;
with Versions; use Versions;
with StrEnc; use StrEnc;
with String_Utils;
with String_Lists;
package Legend is
   use type SDL.Video.Surface_Access_t;



   World_Width      : constant := 480;
   World_Height     : constant := 480;
   Room_Width       : constant := 64;
   Room_Height      : constant := 64;
   War_Field_Width  : constant := 64;
   War_Field_Height : constant := 64;
   Stage_Count      : constant := 84;
   War_Stage_Count  : constant := 26;

   No_Scene         : constant := 16#FFFF#;
   No_Item          : constant := 16#FFFF#;
   No_Hero          : constant := 16#FFFF#;
   No_Picture       : constant := 16#FFFF#;
   No_Story         : constant := 16#FFFF#;
   No_Script        : constant := 16#FFFF#;
   No_Talk          : constant := 16#FFFF#;
   No_Kongfu        : constant := 16#FFFF#;
   No_Effect        : constant := 16#FFFF#;
   No_Game          : constant := 16#FFFF#;
   No_Music         : constant := 16#FFFF#;
   No_Sound         : constant := 16#FFFF#;
   No_Shop          : constant := 16#FFFF#;

   Empty_Grid       : constant := 16#FFFF#;

   Unchanged        : constant := 16#FFFE#;

   Kongfu_Exp_Per_Level : constant := 100;
   Max_Hero_Level       : constant := 30;

   Loop_Infinite    : constant Duration := Duration'Last;

   User_Event_Code_Timer : constant := 1;

   type Byte_Array is array (Positive range <>) of Uint8_t;

   type Uint16_Array is array (Positive range <>) of Uint16_t;

   type Uint16_Array_Access is access Uint16_Array;

   package Uint16_Lists is new Doubly_Linked_Lists (Uint16_t);

   type Int16_Array is array (Positive range <>) of Int16_t;

   type Bounded_State_Type is record
      Now : Int16_t; -- 当前值
      Max : Int16_t; -- 最大值
   end record;

   type Range_Type is record
      Min : Int16_t;
      Max : Int16_t;
   end record;

   Degree_Range : constant Range_Type := (0, 100);
   Points_Range : constant Range_Type := (0, 999);
   Levels_Range : constant Range_Type := (1, 10);

   procedure Add (X : in out Int16_t; V : Int16_t; R : Range_Type);

   procedure Add (S : in out Bounded_State_Type; V : Int16_t);

   procedure Sub (S : in out Bounded_State_Type; V : Int16_t);

   type Point_Type is record
      x, y : Int16_t;
   end record;

   function Hash is new Ada.Unchecked_Conversion (Point_Type, Hash_Type);

   type Point_Array is array (Positive range <>) of Point_Type with Pack;

   package Point_Lists is new Doubly_Linked_Lists (Point_Type);

   package Point_Sets is new Hashed_Sets (Point_Type, Hash, "=");

   -- 坐标列表
   type Coordinates_Type (Count : Natural) is record
      X : Int16_Array (1 .. Count);
      Y : Int16_Array (1 .. Count);
   end record with Pack;

   -- 人物朝向 
   -- 注意: 方向顺序同时用于计算贴图编号，因此不要改变它的顺序
   type Face_Type is (North, East, West, South)
   with Size => 16, Stream_Size => 16;

   Face_To_Offset : constant array (Face_Type) of Point_Type := (
      East  => (x => 1,  y => 0),
      West  => (x => -1, y => 0),
      South => (x => 0,  y => 1),
      North => (x => 0,  y => -1));

   function Offset_To_Face (Offset : Point_Type) return Face_Type
      with Pre => (Offset.x = 0 or Offset.y = 0) and Offset.x /= Offset.y;

   procedure Move_By_Face (
      Position : in out Point_Type;
      Face     : Face_Type;
      Steps    : Int16_t := 1
      );

   function Get_Steps (Offset : Point_Type) return Int16_t;

   function Distance (P, Q : Point_Type) return Int16_t;

   type Attack_Kind_Type is (ak_Throw, ak_Fist, ak_Sword, ak_Blade, ak_Special)
   with Size => 16, Stream_Size => 16;

   type Attack_Kind_Indexed_Values is array(Attack_Kind_Type range <>) of Uint16_t;

   subtype Values_Of_Attack_Kind is Attack_Kind_Indexed_Values(Attack_Kind_Type);

   type Picture_Type is record
      Position : Point_Type;                 -- 像素偏移
      Surface  : SDL.Video.Surface_Access_t; -- 位图数据
   end record;

   type Pictures_Type is array (Uint16_t range <>) of Picture_Type;

   type Pictures_Pointer is access Pictures_Type;

   type Pictures_Array_Type is array (Uint16_t range <>) of Pictures_Pointer;

   type Pictures_Array_Pointer is access Pictures_Array_Type;

   subtype Color_Type is SDL.Video.Color_t;
   -- subtype Color_Type is uint32_t;

   type Palette_256 is array (Uint8_t) of Color_Type;

   type Palette_Access is access Palette_256;

   -- 区域信息
   type Region_Type is record
      Top_Left     : Point_Type;
      Bottom_Right : Point_Type;
   end record;

   package Region_Lists is new Doubly_Linked_Lists (Region_Type);

   type View_Corners_Type is record
      TR : Point_Type; -- 玩家视觉区域右上角对应的地图位置
      BL : Point_Type; -- 玩家视觉区域左下角对应的地图位置
      TL : Point_Type; -- 玩家视觉区域左上角对应的地图位置
      BR : Point_Type; -- 玩家视觉区域右下角对应的地图位置
   end record;

   -- 动画序列信息
   type Movie_Type is record
      Pictures : Pictures_Pointer; -- 资源目录
      First    : Uint16_t;         -- 入口贴图在资源目录中的编号
      Total    : Positive;         -- 总帧数
      Index    : Natural;          -- 当前帧
      Interval : Duration;         -- 贴图切换间隔
      Timer    : Hash_Type;
   end record;

   -- 动画组信息(连续存放多个动作动画, 每个动作的帧数是相同的)
   type Movie_Group_Type is record
      Frame_Entry : Uint16_t; -- 组动画入口帧
      Frame_Count : Uint16_t; -- 各动作帧数
   end record;

   -- 根据动画组获取指定动作动画
   procedure Get_Action_Movie_From_Group (
      Group        : Movie_Group_Type; 
      Action_Index : Uint16_t;
      Action_Movie : in out Movie_Type
      );

   type Confirm_Type is (No, Yes) 
   with Size => 16, Stream_Size => 16;

   type Story_Movie_Type is record
      Story_Id : Uint16_t;  
      First    : Uint16_t;
      Last     : Uint16_t;
   end record;

   type Story_Movie_Array_Type is array(Positive range <>) of Story_Movie_Type;

   type Movie_Frame_Type is record
      First   : Uint16_t; 
      Last    : Uint16_t;
      Current : Uint16_t;
   end record;

   type Script_Cause_Type is (sc_Space, sc_Item, sc_Walk);

   type Script_Of_Cause is array(Script_Cause_Type range <>) of Uint16_t;

   -- 场景的triggers层中存放事件编号(-1表示无事件)
   -- 玩家走动时, 检查相应位置是否有路过事件?如是则执行路过事件的脚本
   -- 玩家按下空格时, 检查下一位置是否有空格事件?如是则执行空格事件脚本
   -- 玩家使用物品时, 检查下一位置是否有物品事件?如是则执行物品事件脚本
   -- d?.grp
   type Story_Type is record
      Visible      : Confirm_Type;                        -- 是否有画面
      Id           : Uint16_t;                            -- 在场景中的事件索引
      Scripts      : Script_Of_Cause(Script_Cause_Type);  -- 脚本列表(kdef) 
      Movie_Frame  : Movie_Frame_Type;                    -- 画面
      Movie_Tick   : Uint16_t;                            -- 
      Position     : Point_Type;                          -- 剧情位置
   end record;

   type Stories_Type is array (Uint16_t range <>) of aliased Story_Type;

   type Stories_Pointer is access Stories_Type;

   type Scene_Stories_Type is array (Uint16_t range <>) of Stories_Pointer;

   type Scene_Stories_Pointer is access Scene_Stories_Type;

   -- 内力性质
   type Magic_Type is (Yin, Yan, Neutral) 
   with Size => 16, Stream_Size => 16;



   type Item_Kind is (
      ik_Story_Item, 
      ik_Equip_Item, 
      ik_Study_Book, 
      ik_Drug_Item, 
      ik_Throw_Item
      ) with Stream_Size => 16, Size => 16;

   type Item_Target is (
      it_Team,
      it_Enemy,
      it_Story
      ) with Size => 16, Stream_Size => 16;
   for Item_Target use (it_Team => 1, it_Enemy => 2, it_Story => 3);

   type Equip_Type is (e_Weapon, e_Armor) with Size => 16, Stream_Size => 16;

   type Equip_Indexed_Values is array(Equip_Type) of Uint16_t;

   type Skill_Type is (
      s_Attack,         -- 攻击力
      s_Movement,       -- 轻功
      s_Defense,        -- 防御力
      s_Cure,           -- 医疗能力
      s_Poison,         -- 用毒能力
      s_Detoxify,       -- 解毒能力
      s_Resistence,     -- 抗毒能力
      s_Fist,           -- 肉搏
      s_Sword,          -- 御剑
      s_Blade,          -- 刀术
      s_Special,        -- 特殊
      s_Throw           -- 暗器
      );

   type Skill_Indexed_Values is array(Skill_Type range <>) of Int16_t;

   subtype Weapon_Skill is Skill_Type range s_Fist .. s_Throw;

   subtype Values_Of_Skill is Skill_Indexed_Values(Skill_Type);

   subtype Values_Of_Weapon is Skill_Indexed_Values(Weapon_Skill);

   subtype Big5_Name is Interfaces.C.char_array;

   function To_UTF8_Name (Name : Big5_Name) return UTF8_String;


   -- 物品对应的贴图即物品编号

   type Item_Type is record
      Id                     : Uint16_t;
      Name                   : Big5_Name(1..20);
      Nickname               : Big5_Name(1..20);
      Description            : Big5_Name(1..30);
      Kongfu                 : Uint16_t;              -- 关联功夫
      Attack_Effect          : Uint16_t;              -- 暗器动画编号
      Owner                  : Uint16_t;              -- 使用人
      Equip                  : Equip_Type;            -- 装备类型
      Show_Description       : Uint16_t;              -- 显示物品说明
      Kind                   : Item_Kind;             -- 类型
      Target                 : Item_Target;           -- 适用对象
      Reserved               : Uint16_Array(1..2);    -- 保留字段
      HP_Bonus               : Bounded_State_Type;    -- 加生命
      WP_Bonus               : Int16_t;               -- 加中毒
      SP_Bonus               : Int16_t;               -- 加体力
      MP_Type                : Magic_Type;            -- 改变内力性质
      MP_Bonus               : Bounded_State_Type;    -- 加内力
      Skill_Bonus            : Values_Of_Skill;       -- 各技能增长
      Knowdge_Bonus          : Int16_t;               -- 加武学常识
      Morality_Bonus         : Int16_t;               -- 加品德
      Attack_Times_Bonus     : Int16_t;               -- 加攻击次数
      Attack_Poison_Bonus    : Int16_t;               -- 加攻击带毒
      Require_Hero           : Uint16_t;              -- 仅修炼人物
      Require_MP_Type        : Magic_Type;            -- 需内力性质
      Require_MP             : Int16_t;               -- 需内力
      Require_Attack         : Int16_t;               -- 需攻击力
      Require_Movement       : Int16_t;               -- 需轻功
      Require_Poison         : Int16_t;               -- 需用毒能力
      Require_Cure           : Int16_t;               -- 需医疗能力
      Require_Detoxify       : Int16_t;               -- 需解毒能力
      Require_Weapon_Skills  : Values_Of_Weapon;      -- 需武器技能
      Require_Wise           : Int16_t;               -- 需资质
      -- for study book 
      Levelup_Exp            : Uint16_t;              -- 升级技能所需经验
      Product_Exp            : Uint16_t;              -- 造出物品需经验
      Require_Material       : Uint16_t;              -- 需材料
      Product_List           : Uint16_Array(1..5);    -- 产品列表
      Material_Count         : Int16_Array(1..5);     -- 所需原料数量
   end record;

   type Items_Type is array (Uint16_t range <>) of Item_Type;

   type Items_Pointer is access Items_Type;

   type Item_Grid_Type is record
      Id    : Uint16_t;
      Count : Int16_t;
   end record;

   type Bag_Type is array (Positive range <>) of Item_Grid_Type;

   type Map_Layer_Type is (
      ml_Earth,      
      ml_Surface, 
      ml_Building, 
      ml_Story, 
      ml_BX, ml_BY,
      ml_Sprite
      ) with Size => 16, Stream_Size => 16;

   type Layer_Type is array(Int16_t range <>, Int16_t range <>) of Uint16_t;

   type Layer_Access is access Layer_Type;

   function In_Bound (Map : Layer_Access; Where : Point_Type) return Boolean;

   type Layer_Array is array(Map_Layer_Type) of Layer_Access;

   type Scene_Maps is array(Uint16_t range <>) of Layer_Array;

   type Scene_Maps_Pointer is access Scene_Maps;

   type Layer_Visibility is array(Map_Layer_Type) of Boolean;

   type Picture_Group is record
      From, To : Uint16_t;
   end record;

   type Picture_Group_Array is array(Positive range <>) of Picture_Group;

   function In_Groups (
      Picture_Id : Uint16_t; 
      Groups     : Picture_Group_Array
      ) return Boolean;

   type Scene_Type is record
      Id                  : Uint16_t;
      Name                : Big5_Name(1..10);
      Leave_Music         : Uint16_t;
      Enter_Music         : Uint16_t;
      Child_Scene         : Uint16_t;             -- 二级场景
      Enter_Condition     : Uint16_t;             -- 进入条件 
      Outer_Entries       : Point_Array(1..2);    -- 外景入口位置列表 
      Door                : Point_Type;           -- 人物进门后的站立位置
      Exits               : Coordinates_Type (3); -- 出口坐标列表
      Child_Scene_Entry   : Point_Type;           -- 二级场景入口
      Child_Scene_Exit    : Point_Type;           -- 二级场景出口(如全0则同上)
   end record;
   -- 52字节
   -- Enter_Condition 可选值如下
   -- 0 : 开启 
   -- 1 : 关闭
   -- 2 : 需轻功(云鹤崖(2), 摩天崖(38))
   -- 对于二级场景, Outer_Entries为(0, 0)

   function Can_Enter (Scene : Scene_Type) return Boolean;

   function Enter_From_World (Scene : Scene_Type) return Boolean;

   type Scenes_Type is array (Uint16_t range <>) of aliased Scene_Type;

   type Scenes_Pointer is access Scenes_Type;

   type Kongfu_Damage_Type is (kd_HP, kd_MP)
   with Size => 16, Stream_Size => 16;

   type Attack_Range_Type is (ar_Point, ar_Line, ar_Cross, ar_Area)
   with Size => 16, Stream_Size => 16;

   subtype Kongfu_Level_Range is Positive range 1 .. 10;

   type Kongfu_Type is record
      Id              : Uint16_t;
      Name            : Big5_Name(1..10);
      Nickname        : Big5_Name(1..10);
      Attack_Sound    : Uint16_t;                         -- 出招音效
      Attack_Kind     : Attack_Kind_Type;                 -- 类型
      Movie_Effect    : Uint16_t;                         -- 效果编号
      Damage_Type     : Kongfu_Damage_Type;               -- 伤害类型
      Range_Type      : Attack_Range_Type;                -- 攻击范围类型
      MP_Consume      : Int16_t;                          -- 消耗内力点数
      Weakness_Damage : Int16_t;                          -- 敌人中毒点数
      Attack          : Int16_Array(Kongfu_Level_Range);  -- 攻击力
      Cast_Range      : Int16_Array(Kongfu_Level_Range);  -- 移动范围
      Damage_Range    : Int16_Array(Kongfu_Level_Range);  -- 杀伤范围
      MP_Bonus        : Int16_Array(Kongfu_Level_Range);  -- 加内力
      MP_Damage       : Int16_Array(Kongfu_Level_Range);  -- 杀内力
   end record;


   type Kongfus_Type is array (Uint16_t range <>) of aliased Kongfu_Type;

   type Kongfus_Pointer is access Kongfus_Type;


   -- 坐骑
   type Horse_Type is (No_Horse, Boat)
   with Size => 16, Stream_Size => 16;

   type Horse_Movie_Groups_Type is array (Horse_Type) of Movie_Group_Type;


   -- 性别
   type Sex_Type is (Man, Woman, Neutral) 
   with Size => 16, Stream_Size => 16;

   type Camp_Type is (k_Player, k_Enemy, k_Neutral);

   function "not" (C : Camp_Type) return Camp_Type;

   subtype Kongfu_Index_Range is Positive range 1 .. 10;

   subtype Kongfu_Id_List is Uint16_Array(Kongfu_Index_Range);

   subtype Kongfu_Exp_List is Int16_Array(Kongfu_Index_Range); 

   type Hero_Type is record
      Id                     : Uint16_t;              -- 编号
      Icon                   : Uint16_t;              -- 对话头像
      HP_Bonus_Per_Level     : Int16_t;               -- 每升一级生命增长值
      Math                   : Int16_t;               -- 奇门循甲能力
      Name                   : Big5_Name(1..10);      -- 姓名
      Nickname               : Big5_Name(1..10);      -- 外号
      Sex                    : Sex_Type;              -- 性别
      Level                  : Uint16_t;              -- 当前等级
      Exp                    : Uint16_t;              -- 当前经验值
      HP                     : Bounded_State_Type;    -- 生命
      Hurt                   : Int16_t;               -- 受伤程度
      Weakness               : Int16_t;               -- 中毒程度
      Stamina                : Int16_t;               -- 体力
      Item_Exp               : Uint16_t;              -- 修炼物品当前经验值
      Equips                 : Equip_Indexed_Values;  -- 装备
      Attack_Movie_Frames    : Values_Of_Attack_Kind; -- 出招动画帧数
      Attack_Effect_Delays   : Values_Of_Attack_Kind; -- 武功效果延迟帧数
      Attack_Music_Delays    : Values_Of_Attack_Kind; -- 武功音效延迟
      MP_Type                : Magic_Type;            -- 内力性质
      MP                     : Bounded_State_Type;    -- 内力
      Skills                 : Values_Of_Skill;
      Knowdge                : Int16_t;               -- 武学常识
      Morality               : Int16_t;               -- 品德
      Attack_Addition_Poison : Int16_t;               -- 攻击带毒
      Attack_Addition_Times  : Int16_t;               -- 左右互搏(0: 否; 1: 是)
      Fame                   : Int16_t;               -- 声望
      Wise                   : Int16_t;               -- 资质
      Learning_Item          : Uint16_t;              -- 修炼物品
      Learning_Exp           : Uint16_t;              -- 修炼物品所需经验值
      Kongfu                 : Kongfu_Id_List;        -- 武功
      Kongfu_Exp             : Kongfu_Exp_List;       -- 武功经验值
      Items                  : Uint16_Array(1..4);    -- 携带物品
      Items_Count            : Int16_Array(1..4);     -- 携带物品数量
   end record;

   function Get_Kongfu_Level (
      Hero  : Hero_Type;
      Index : Kongfu_Index_Range
      ) return Kongfu_Level_Range;

   function Get_Kongfu_Index (
      Hero   : Hero_Type;
      Kongfu : Uint16_t;
      Index  : in out Kongfu_Index_Range
      ) return Boolean; 

   function Compute_Book_Levelup_Exp (
      Hero : Hero_Type; 
      Book : Item_Type
      ) return Uint16_t;

   function Compute_Levelup_Exp (
      Hero : Hero_Type
      ) return Uint16_t;

   procedure Level_Up (
      Hero : in out Hero_Type; 
      Exp  : Uint16_t
      );

   function Study_Kongfu (
      Hero  : in out Hero_Type;
      Book  : Item_Type; 
      Exp   : Uint16_t
      ) return Boolean;

   -- return product id or No_Item
   function Study_Make (
      Hero : in out Hero_Type;
      Book : Item_Type; 
      Exp  : Uint16_t
      ) return Uint16_t;

   function Study_Skill (
      Hero : in out Hero_Type;
      Book : Item_Type;
      Exp  : Uint16_t
      ) return Boolean;

   function Get_Skill (
      Hero : Hero_Type;
      Skill : Skill_Type
      ) return Int16_t;

   procedure Reset_State (Hero : in out Hero_Type);

   procedure Apply_Item_Bonus (Hero : in out Hero_Type; Item : Item_Type);

   function Match_Require (Hero : Hero_Type; Item : Item_Type) return Boolean;

   procedure Equip_Book (
      Hero : in out Hero_Type;
      Book : in out Item_Type
      );

   procedure Unequip_Book (Hero : in out Hero_Type);

   procedure Equip_Item (
      Hero : in out Hero_Type;
      Item : in out Item_Type
      );

   procedure Unequip_Item (
      Hero  : in out Hero_Type;
      Equip : Equip_Type
      );


   function Get_Radius (
      Hero  : Hero_Type;
      Skill : Skill_Type
      ) return Int16_t
      with Pre => Skill in s_Movement | s_Cure | s_Poison | s_Detoxify | s_Throw;

   procedure Compute_Kongfu_Damage (
      Attacker  : in out Hero_Type;     -- 攻方
      Defender  : in out Hero_Type;     -- 守方
      Kongfu    : Kongfu_Type;          -- 攻方武功
      Level     : Kongfu_Level_Range;   -- 武功级别
      A_Knowdge : Int16_t;              -- 攻方武学常识
      D_Knowdge : Int16_t;              -- 守方武学常识
      Damage    : out Int16_t           -- 杀伤值
      );

   procedure Apply_Cure (
      Doctor, Patient : in out Hero_Type; 
      Bonus : out Int16_t
      );

   procedure Apply_Detoxify (
      Doctor, Patient : in out Hero_Type; 
      Bonus : out Int16_t
      );

   function Get_Attack_Movie (
      Hero  : Hero_Type; 
      Kind  : Attack_Kind_Type;
      Face  : Face_Type;
      Movie : out Movie_Type
      ) return Boolean;

   procedure Get_FBK_Movie (
      Kind  : Attack_Kind_Type;
      Face  : Face_Type;
      Movie : out Movie_Type
      ) with Pre => Kind in ak_Fist | ak_Sword | ak_Blade;

   function Get_Effect_Movie (Index : Uint16_t) return Movie_Type;

   type Heroes_Type is array (Uint16_t range <>) of aliased Hero_Type;

   type Heroes_Pointer is access Heroes_Type;

   type Shop_Type is record
      Item  : Uint16_Array(1..5);
      Count : Uint16_Array(1..5);
      Price : Int16_Array(1..5);
   end record with Pack;

   type Shops_Type is array (Uint16_t range <>) of aliased Shop_Type;

   type Shops_Pointer is access Shops_Type;

   function Get_Shop_By_Scene (Scene_Id : UInt16_t) return Uint16_t;

   -- 基本信息 : 36 + 200 * 4字节
   type Leader_State_type is record
      Horse              : Horse_Type;
      Reserved           : Uint16_t; -- 似乎无用
      Position_At_World  : Point_Type;
      Position_At_Room   : Point_Type;
      Face               : Face_Type;
      Boat_Head_Position : Point_Type;
      Boat_Tail_Position : Point_Type;
      Boat_Face          : Face_Type;
      Team               : Uint16_Array(1..6); -- 战队
      Bag                : Bag_Type(1..200);   -- 物品清单
   end record;

   type Talks_type is array (Uint16_t range <>) of String_Access;

   type Talks_Pointer is access Talks_Type;

   -- r*.grp
   type World_Record_Type is limited record
      Leader  : Leader_State_Type;   -- 主角及船只位置, 战队, 背包
      Heroes  : Heroes_Pointer;      -- 所有英雄定义
      Items   : Items_Pointer;       -- 所有物品定义
      Scenes  : Scenes_Pointer;      -- 所有场景位置及音乐定义
      Kongfus : Kongfus_Pointer;     -- 所有功夫定义
      Shops   : Shops_Pointer;       -- 所有商店定义
   end record;

   type World_Record_Pointer is access World_Record_Type;

   type War_Hero_List (Count : Natural) is record
      Id : Uint16_Array(1 .. Count); -- 参战英雄列表
      X  : Int16_Array (1 .. Count); -- 地图横坐标
      Y  : Int16_Array (1 .. Count); -- 地图纵坐标
   end record;

   -- war.sta 
   type War_Define_Type is record
      Id              : Uint16_t;           -- 编号
      Name            : Big5_Name(1..10);   -- 名称
      Scene           : Uint16_t;           -- 战斗场景代号(0..25)
      Exp             : Uint16_t;           -- 总经验值
      Music           : Uint16_t;           -- 背景音乐
      Required_Heroes : Uint16_Array(1..6); -- 必须参战的英雄
      Heroes          : War_Hero_List(6);   -- 我方战队
      Enemies         : War_Hero_List(20);  -- 敌方战队
   end record;
   -- 地图数据在warfld.grp中, 场景资源在wmp???中
   -- 如果Required_Heroes非空, 则由玩家通过菜单从战队中选择参战英雄;
   -- 否则使用预设的人物直接进入
   -- 共140场战斗(其中136-139是空的)
   -- 战场人物的贴图计算公式为: 2553 + 人物编号 * 4 + 方向

   type War_Defines_Type is array (
      Uint16_t range <>
      ) of aliased War_Define_Type;

   type War_Defines_Pointer is access War_Defines_Type;

   -- 这些数据存储在r*.grp中
   All_World : World_Record_Pointer := null;

   -- 这些数据存储在d*.grp中
   All_Scene_Stories : Scene_Stories_Pointer := null;

   -- 这些数据存储在s*.grp中
   All_Scene_Maps : Scene_Maps_Pointer := null;

   procedure Set_Game (Game_Index : Uint16_t);

   procedure Load_States;

   procedure Save_States (To : Uint16_t);

   procedure Trace_Log (S : String);

   SDL_Error : Exception;

private

   Rnd_Generator : GNAT.Random_Numbers.Generator;

   function Random_Natural is
      new GNAT.Random_Numbers.Random_Discrete(Natural);

   function Random_Int16 is
      new GNAT.Random_Numbers.Random_Discrete(Int16_t);

   function JY_Path return String;
   -- 游戏资源目录(from config file : legend.conf => legend.path)

   Gameover : Boolean := False;

   package Data_Files is
      type Scene_Maps    is (allsin, s1, s2, s3);
      type State_Records is (ranger, r1, r2, r3);
      type Scene_Storys  is (alldef, d1, d2, d3);

      Current_Index : Uint16_t := No_Game;
      -- 当前存档编号

      function Current_Scene_Maps_Filename return String;

      function Current_State_Record_Filename return String;

      function Current_Defines_Filename return String;

   end Data_Files;

   function To_Int16 is 
      new Ada.Unchecked_Conversion (Uint16_t, SDL.Int16_t);

   function To_Uint16 is 
      new Ada.Unchecked_Conversion (SDL.Int16_t, Uint16_t);

   function "&" (left : String; right : Uint16_t) return String with Inline;

   function "&" (left : String; right : Int16_t) return String with Inline;

   procedure Add (p : in out Point_Type; by : Point_Type);

   function "+" (left, right : Point_Type) return Point_Type with Inline;

   function "-" (left, right : Point_Type) return Point_Type with Inline;

   function "*" (left, right : Point_Type) return Point_Type with Inline;

   function "-" (x : Face_Type) return Face_Type;

   function In_Region (P : Point_Type; R : Region_Type) return Boolean;

   function Width (r : Region_Type) return Int16_t with Inline;

   function Height (r : Region_Type) return Int16_t with Inline;

   procedure Convert (from : Region_Type; to : out SDL.Video.Rect_T);

   function Freq (Interval : Duration) return Duration with Inline;

   function Interval (Freq : Duration) return Duration with Inline;

   -- 切换到下一帧
   procedure Next_Frame (movie : in out Movie_Type);

   function Length (Movie : Movie_Type) return Duration with Inline;


   procedure Next_Frame (Movie_Frame : in out Movie_Frame_Type);

   function Wise_To_Rate (Wise : Int16_t) return Uint16_t;

   function Is_Item_Enougth (
      Id : Uint16_t;
      Count : Int16_t
      ) return Boolean;

   procedure Dispose is
      new Ada.Unchecked_Deallocation (Pictures_Type, Pictures_Pointer);

   procedure Dispose is
      new Ada.Unchecked_Deallocation(Uint16_Array, Uint16_Array_Access);

   procedure Dispose is
      new Ada.Unchecked_Deallocation (Stories_Type, Stories_Pointer);

   procedure Dispose (p : in out Scene_Stories_Pointer);

   procedure Dispose is 
      new Ada.Unchecked_Deallocation (War_Defines_Type, War_Defines_Pointer);

   procedure Dispose is
      new Ada.Unchecked_Deallocation (Items_Type, Items_Pointer);

   procedure Dispose is
      new Ada.Unchecked_Deallocation (Scenes_Type, Scenes_Pointer);

   procedure Dispose is
      new Ada.Unchecked_Deallocation (Kongfus_Type, Kongfus_Pointer);

   procedure Dispose is
      new Ada.Unchecked_Deallocation (Heroes_Type, Heroes_Pointer);

   procedure Dispose is
      new Ada.Unchecked_Deallocation (Shops_Type, Shops_Pointer);

   procedure Dispose (pa : in out Pictures_Array_Pointer);

   procedure Dispose is 
      new Ada.Unchecked_Deallocation(Layer_Type, Layer_Access);

   procedure Dispose is
      new Ada.Unchecked_Deallocation(Scene_Maps, Scene_Maps_Pointer);

   procedure Dispose is
      new Ada.Unchecked_Deallocation(World_Record_Type, World_Record_Pointer);

end Legend;
